﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using PSE.ProcessManager.Entity;

namespace ConfigurationManager.Model
{
    public class ProductExportInfo
    {
        /// <summary>
        /// Nome do Produto
        /// </summary>
        public string ProductName
        {
            get;
            set;
        }

        public string ProcessesFolderPath
        {
            get;
            set;
        }

        public string STSAuthorityCertificateName
        {
            get;
            set;
        }

        public string ServiceCertificateName
        {
            get;
            set;
        }
    }

    public class Exporter
    {
        /// <summary>
        /// Como todos os produtos possuem os mesmos inteligence modules, recuperar apenas uma vez do banco e reutilizar
        /// </summary>
        private static List<InteligenceModuleEntity> _inteligenceModulesToExport;

        private static object _syncRoot = new object();

        /// <summary>
        /// Exportar dados de uma lista de produtos
        /// </summary>
        /// <param name="products"></param>
        /// <param name="outputPath"></param>
        public static void Export(ProductExportInfo exportInfo)
        {
            if (string.IsNullOrEmpty(exportInfo.ProductName))
                throw new ValidationException("O nome do produto deve ser informado.");

            if (string.IsNullOrEmpty(exportInfo.ProcessesFolderPath))
                throw new ValidationException("O caminho do diretório de assemblies dos processos deve ser informado.");

            if (string.IsNullOrEmpty(exportInfo.STSAuthorityCertificateName))
                throw new ValidationException("O nome do certificado 'STS Authority' deve ser informado.");

            if (string.IsNullOrEmpty(exportInfo.ServiceCertificateName))
                throw new ValidationException("O nome do certificado 'Service' deve ser informado.");

            PSE.ProcessManager.ConfigurationManager.ConfigurationManager configurationManager = new PSE.ProcessManager.ConfigurationManager.ConfigurationManager();

            string outputPath = Path.Combine(configurationManager.ProcessManagerPath, "Server");

            Model.Product product = Model.Product.RetrieveByName(exportInfo.ProductName);

            if (product == null)
            {
                throw new ValidationException(string.Format("O produto {0} não está cadastrado.", exportInfo.ProductName));
            }
            else
            {
                if (configurationManager.ListProducts().Any(p => p == exportInfo.ProductName))
                    configurationManager.RemoveProduct(exportInfo.ProductName);

                configurationManager.AddProduct(exportInfo.ProductName);

                string dirPath = outputPath + @"\Instances";
                //CreateDirectory(dirPath);

                string productInstancesDirPath = dirPath + @"\" + product.Name;

                ////criar diretório para o produto
                //Directory.CreateDirectory(productInstancesDirPath);

                ExportInstances(exportInfo, productInstancesDirPath, product);
            }
        }

        //private static void CreateDirectory(string dirPath)
        //{
        //    if (!Directory.Exists(dirPath))
        //        Directory.CreateDirectory(dirPath);
        //}

        /// <summary>
        /// Exportar instancias de um produto
        /// </summary>
        /// <param name="productDirPath"></param>
        /// <param name="product"></param>
        private static void ExportInstances(ProductExportInfo exportInfo, string productInstancesDirPath, Model.Product product)
        {
            PSE.ProcessManager.ConfigurationManager.ConfigurationManager configurationManager = new PSE.ProcessManager.ConfigurationManager.ConfigurationManager();

            //recuperar as instancias de um produto
            product.Instances = Model.Instance.RetrieveByProduct(product.Id);
            if (product.Instances != null)
            {
                List<InstanceEntity> instancesToExport = new List<InstanceEntity>();
                //string instanceDirPath, dataFilesDirPath;
                foreach (Model.Instance instance in product.Instances)
                {
                    //gerar arquivo com inteligence modules
                    ExportInteligenceModules();

                    configurationManager.AddInstance(exportInfo.ProductName,
                                                     instance.Name,
                                                     instance.Address,
                                                     exportInfo.ProcessesFolderPath,
                                                     exportInfo.STSAuthorityCertificateName,
                                                     exportInfo.ServiceCertificateName,
                                                     _inteligenceModulesToExport);

                    //criar diretorio para armazenar os configs da instancia e os arquivos de dados
                    //instanceDirPath = productInstancesDirPath + @"\" + instance.Name;
                    //CreateDirectory(instanceDirPath);

                    ////criar configs
                    ////criar config inteligence manager
                    //GenerateInteligenceManagerConfig(exportInfo, instanceDirPath, instance);
                    ////criar config executor
                    //GenerateExecutorConfig(exportInfo, instanceDirPath, instance);


                    //criar diretorios para armazenar arquivos de dados
                    //dataFilesDirPath = instanceDirPath + @"\Data\Files";
                    //CreateDirectory(dataFilesDirPath);

                    //PSE.ProcessManager.Entity.InstanceEntity instanceEntity = new PSE.ProcessManager.Entity.InstanceEntity();
                    //instanceEntity.Name = instance.Name;
                    //instanceEntity.Address = instance.Address;

                    //instance.Processes = Model.Process.RetrieveByInstance(instance.Id);
                    //if (instance.Processes != null)
                    //{
                    //    instanceEntity.ProcessIds = new List<int>();
                    //    foreach (Model.Process p in instance.Processes)
                    //        instanceEntity.ProcessIds.Add(p.Id);
                    //}

                    //instancesToExport.Add(instanceEntity);

                    List<Model.Process> processes = Model.Process.RetrieveByInstance(instance.Id, true);
                    
                    foreach (Model.Process im in processes)
                    {
                        configurationManager.AddProcess(
                            exportInfo.ProductName, 
                            instance.Name, 
                            new ProcessEntity()
                            {
                                Id = im.Id,
                                Name = im.Name,
                                Assembly = im.Assembly,
                                Class = im.Class,
                                Description = im.Description,
                                InitializationType = im.InitializationType.GetValueOrDefault(),
                                InstanceContext = im.InstanceContext.GetValueOrDefault(),
                                InteligenceModuleId = im.InteligenceModule.Id,
                                FailureRecovery = im.FailureRecovery
                            });
                    }

                    //gerar arquivo de processos
                    //ExportProcesses(dataFilesDirPath, instance);
                }

                //PSE.Framework.Serialization.XmlSerializer serializer = new PSE.Framework.Serialization.XmlSerializer(typeof(List<InstanceEntity>));
                //serializer.SerializeToFile(productInstancesDirPath + @"\Instances.config", instancesToExport);
            }
        }

        /// <summary>
        /// Exportar os inteligence modules
        /// </summary>
        /// <param name="dataFilesDirPath"></param>
        private static void ExportInteligenceModules(/*string dataFilesDirPath*/)
        {
            lock (_syncRoot)
            {
                if (_inteligenceModulesToExport == null)
                {
                    List<Model.InteligenceModule> inteligenceModules = Model.InteligenceModule.Retrieve();
                    _inteligenceModulesToExport = new List<InteligenceModuleEntity>();
                    foreach (Model.InteligenceModule im in inteligenceModules)
                    {
                        _inteligenceModulesToExport.Add(new InteligenceModuleEntity()
                        {
                            Id = im.Id,
                            Name = im.Name,
                            Description = im.Description,
                            Class = im.Class,
                            Assembly = im.Assembly
                        });
                    }
                }
            }

            //PSE.Framework.Serialization.XmlSerializer serializer = new PSE.Framework.Serialization.XmlSerializer(typeof(List<InteligenceModuleEntity>));
            //serializer.SerializeToFile(dataFilesDirPath + @"\InteligenceModules.xml", _inteligenceModulesToExport);
        }

        /// <summary>
        /// Exportar os processos de uma instancia
        /// </summary>
        /// <param name="dataFilesDirPath"></param>
        /// <param name="instance"></param>
        //private static void ExportProcesses(string dataFilesDirPath, Instance instance)
        //{
        //    List<Model.Process> processes = Model.Process.RetrieveByInstance(instance.Id);
        //    List<ProcessEntity> processToExport = new List<ProcessEntity>();
        //    foreach (Model.Process im in processes)
        //    {
        //        processToExport.Add(new ProcessEntity()
        //        {
        //            Id = im.Id,
        //            Name = im.Name,
        //            Assembly = im.Assembly,
        //            Class = im.Class,
        //            Description = im.Description,
        //            InitializationType = im.InitializationType.GetValueOrDefault(),
        //            InstanceContext = im.InstanceContext.GetValueOrDefault(),
        //            InteligenceModuleId = im.InteligenceModule.Id,
        //            FirstFailureRecovery = im.FirstFailureRecovery,
        //            SecondFailureRecovery = im.SecondFailureRecovery,
        //            SubsequentFailuresRecovery = im.SubsequentFailuresRecovery
        //        });
        //    }

        //    PSE.Framework.Serialization.XmlSerializer serializer = new PSE.Framework.Serialization.XmlSerializer(typeof(List<ProcessEntity>));
        //    serializer.SerializeToFile(dataFilesDirPath + @"\Processes.xml", processToExport);
        //}
    }
}
